package com.aqielife.netty.protocol;

import com.aqielife.netty.message.Message;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

/**
 * 必须和 @link{LengthFieldBasedFrameDecoder} 一起使用，确保接到的 ByteBuf 消息是完整的
 * */
@ChannelHandler.Sharable
@Slf4j
public class MessageCodecSharable extends MessageToMessageCodec<ByteBuf, Message> {
    /***
     * 编码
     */
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> out) throws Exception {
        ByteBuf outTemp = ctx.alloc().buffer();
        //1. 4 字节表示魔数
        outTemp.writeBytes(new byte[]{1,2,3,4});
        //2. 1 字节表示版本
        outTemp.writeByte(1);
        //3. 1 字节表示序列化方式,0 jdk,1 json
        outTemp.writeByte(0);
        //4. 1 字节表示指令类型
        outTemp.writeByte(msg.getMessageType());
        //5. 4 字节表示序列号
        outTemp.writeInt(msg.getSequenceId());

        // 上述和为15，为了满足2^n倍，让内存对齐。填入一个无意义字节
        outTemp.writeByte(0xff);

        //6. 获取内容的字节数组
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(msg);
        byte[] bytes = byteArrayOutputStream.toByteArray();

        //7. 4字节表示长度
        outTemp.writeInt(bytes.length);
        //8. 写入内容
        outTemp.writeBytes(bytes);
        objectOutputStream.close();
        byteArrayOutputStream.close();
        out.add(outTemp);
    }

    /**
     * 解码
     * */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        int magicNum = in.readInt();
        byte version = in.readByte();
        byte serializerAlgorithm = in.readByte(); // 0 或 1
        byte messageType = in.readByte();         // 0,1,2...
        int sequenceId = in.readInt();
        in.readByte();
        int length = in.readInt();
        byte[] bytes = new byte[length];
        /**
         * 从当前读指针位置开始读
         * */
        in.readBytes(bytes,0,length);
        // 找到反序列化算法
        Serializer.Algorithm algorithm = Serializer.Algorithm.values()[serializerAlgorithm];
        // 确定具体消息类型
        Class<? extends Message> messageClass = Message.getMessageClass(messageType);
        Message message = algorithm.deserialize(messageClass, bytes);
        //log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerAlgorithm, messageType, sequenceId, length);
        //log.debug("{}", message);
        out.add(message);
    }
}
